﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Tetris
{
    public class GameLogic
    {
        public int fieldWidth;
        public int fieldHeight;
        public InputHandler _userInputHandler = new InputHandler();
        private int _delay = 500;
        public int posRotate = 0;
        private int _posX = 0;
        private Field field = new Field();
        private Rotate rot = new Rotate();
        

        
        public GameLogic(InputHandler inputHandler)
        {
            _userInputHandler = inputHandler;
            
        }
        public void StartGame(int fieldHeight, int fieldWidth)
        {
            Console.SetWindowSize(fieldWidth, fieldHeight);
            _userInputHandler.RotateShape += OnRotateShape;
            _userInputHandler.SpeedUp += OnSpeedUpRequest;
            _userInputHandler.SpeedDown += OnSpeedDownRequest;
            _userInputHandler.MoveShapeLeft += OnMoveLeftRequest;
            _userInputHandler.MoveShapeRight += OnMoveRightRequest; 
            field.GameField();
            Game();

        }

        public void Game ()
        {

            int q = field.ChooseRandomShape();
            Shape shape = field.Sh.MyShapes[q];
            field.initDefoultShapePos(shape);
            int i = 0;
            do
            {
               
                if (canMoveDown(shape, i, field.state))
                {
                    
                    field.rend.ClearPriviosPosition(shape.b1.x + _posX, shape.b1.y,
                                     shape.b2.x + _posX, shape.b2.y,
                                     shape.b3.x + _posX, shape.b3.y,
                                     shape.b4.x + _posX, shape.b4.y);
                    _userInputHandler.QueryKeyBoard();
                    
                    
                    
                    RotateShape(q, shape);
                    field.moveShape(shape);
                    ChekMoveRight(shape, field.state);
                    ChekMoveLeft(shape, field.state);
                    field.rend.RenderShape(shape.b1.x + _posX, shape.b1.y,
                                     shape.b2.x + _posX, shape.b2.y,
                                     shape.b3.x + _posX, shape.b3.y,
                                     shape.b4.x + _posX, shape.b4.y);
                    i++;
                    Thread.Sleep(_delay);
                }
                else
                {
                    saveShapePosition(shape);
                    posRotate = 0;

                    if (!ClearLine(field.state))
                    {
                        ClearLine(field.state);
                        AfterCleanMoveDown(field.state);
                    }
                    
                    _posX = 0;
                    Game();
                    if (i == 0)
                    {
                        Console.WriteLine("Game over");
                        break;
                    }

                }
            } while (i != 1000);
            Game();
        }
        public void saveShapePosition(Shape shape)
        {
            field.state[shape.b1.x + _posX, shape.b1.y] = 1;
            field.state[shape.b2.x + _posX, shape.b2.y] = 1;
            field.state[shape.b3.x + _posX, shape.b3.y] = 1;
            field.state[shape.b4.x + _posX, shape.b4.y] = 1;
        }

        public void RotateShape(int q, Shape sh)
        {
            switch (q)
            {
                case 0:
                    if (posRotate == 1)
                    {
                        rot.RotateIPos2(sh);
                        posRotate = 2;
                        break;
                    }
                    if (posRotate == 3)
                    {
                        rot.RotateIPosDef(sh);
                        posRotate = 0;
                        break;
                    }
                    break;
                case 1:
                    if (posRotate == 1)
                    {
                        rot.RotateLPos2(sh);
                        posRotate = 2;
                        break;
                    }
                    if (posRotate == 3)
                    {
                        rot.RotateLPos3(sh);
                        posRotate = 4;
                        break;
                    }
                    if (posRotate == 5)
                    {
                        rot.RotateLPos4(sh);
                        posRotate = 6;
                        break;
                    }
                    if (posRotate == 7)
                    {
                        rot.RotateLPosDef(sh);
                        posRotate = 0;
                        break;
                    }
                    break;
                case 2:
                   if (posRotate == 1)
                    {
                        rot.RotateJPos2(sh);
                        posRotate = 2;
                        break;
                    }
                    if (posRotate == 3)
                    {
                        rot.RotateJPos3(sh);
                        posRotate = 4;
                        break;
                    }
                    if (posRotate == 5)
                    {
                        rot.RotateJPos4(sh);
                        posRotate = 6;
                        break;
                    }
                    if (posRotate == 7)
                    {
                        rot.RotateJPosDef(sh);
                        posRotate = 0;
                        break;
                    }
                    break;
                case 3:
                   if (posRotate == 1)
                    {
                        rot.RotateTPos2(sh);
                        posRotate = 2;
                        break;
                    }
                    if (posRotate == 3)
                    {
                        rot.RotateTPos3(sh);
                        posRotate = 4;
                        break;
                    }
                    if (posRotate == 5)
                    {
                        rot.RotateTPos4(sh);
                        posRotate = 6;
                        break;
                    }
                    if (posRotate == 7)
                    {
                        rot.RotateTPosDef(sh);
                        posRotate = 0;
                        break;
                    }
                    break;
                case 4:
                    if (posRotate == 1)
                    {
                        rot.RotateSPos2(sh);
                        posRotate = 2;
                        break;
                    }
                    if (posRotate == 3)
                    {
                        rot.RotateSPosDef(sh);
                        posRotate = 0;
                        break;
                    }
                    break;
                case 5:
                    if (posRotate == 1)
                    {
                        rot.RotateZPos2(sh);
                        posRotate = 2;
                        break;
                    }
                    if (posRotate == 3)
                    {
                        rot.RotateZPosDef(sh);
                        posRotate = 0;
                        break;
                    }
                    break;
                case 6:
                    break;

            }

        }

        public bool ClearLine(int[,] state)
        {
            bool spase = true;
            for (int y = 24; y > 5; y--)
            {
                for (int x = 6; x < 20; x++)
                {

                    if (state[x, y] == 1)
                    {
                        spase = true;
                    }
                    if (state[x, y] == 0)
                    {
                        spase = false;
                        break;
                    }
                }

                if (spase)
                {
                    for (int x = 6; x < 20; x++)
                    {
                        state[x, y] = 0;
                        field.rend.CleanInit(x, y);

                    }
                   
                }
                
            }
            return true;
            
        }

        public void AfterCleanMoveDown(int[,] state)
        {
            for (int y = 24; y > 5; y--)
                for (int x = 6; x < 20; x++)
                {
                    if (state[x, y] == 1)
                    {
                        state[x, y + 1] = 1;
                        state[x, y] = 0;
                        field.rend.CleanInit(x, y);
                        field.rend.RenderInit(x, y + 1);

                    }
                }

        }



        public bool canMoveDown(Shape shape, int step, int[,] state)
        {

            return state[shape.b1.x + _posX, shape.b1.y + 1] == 0
                && state[shape.b2.x + _posX, shape.b2.y + 1] == 0
                && state[shape.b3.x + _posX, shape.b3.y + 1] == 0
                && state[shape.b4.x + _posX, shape.b4.y + 1] == 0;
            
        }
        public void ChekMoveRight(Shape shape, int[,] state)
        {
            if (state[shape.b1.x + _posX, shape.b1.y] == 1
                || state[shape.b2.x + _posX, shape.b2.y] == 1
                || state[shape.b3.x + _posX, shape.b3.y] == 1
                || state[shape.b4.x + _posX, shape.b4.y] == 1)
            {
                _posX --;
            }
        }
        public void ChekMoveLeft(Shape shape, int[,] state)
        {

            if (state[shape.b1.x + _posX, shape.b1.y] == 1
               || state[shape.b2.x + _posX, shape.b2.y] == 1
               || state[shape.b3.x + _posX, shape.b3.y] == 1
               || state[shape.b4.x + _posX, shape.b4.y] == 1)
            {
                _posX += 2;
            }
        }
        private void OnRotateShape(object sender, EventArgs e)
        {
           posRotate += 1;

            //Debug.WriteLine("Delay has been increased to {0}", delay);
        }
        private void OnSpeedDownRequest(object sender, EventArgs e)
        {
            _delay += 100;
            //Debug.WriteLine("Delay has been increased to {0}", _delay);
        }

        private void OnSpeedUpRequest(object sender, EventArgs e)
        {
            if (_delay >= 100)
                _delay -= 100;


           // Debug.WriteLine("Delay has been decreased to {0}", _delay);
        }
        private void OnMoveRightRequest(object sender, EventArgs e)
        {
            _posX += 1;
           // Debug.WriteLine("Delay has been decreased to {0}", _delay);
        }
        private void OnMoveLeftRequest(object sender, EventArgs e)
        {
            _posX -= 1;
           // Debug.WriteLine("Delay has been decreased to {0}", _delay);
        }
            
        
    }
}
